home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume2 / msdos-pipes < prev    next >
Encoding:
Internet Message Format  |  1991-08-07  |  14.4 KB

  1. From: reynolds@uunet.uu.net@hsvpmi.UUCP
  2. Newsgroups: comp.sources.misc
  3. Subject: v02i068: UN*X pipes for MSDOS
  4. Message-ID: <7471@ncoast.UUCP>
  5. Date: 5 Mar 88 23:09:36 GMT
  6. Approved: allbery@ncoast.UUCP
  7.  
  8. Comp.sources.misc: Volume 2, Issue 68
  9. Submitted-By: "A. Nonymous" <reynolds@uunet.uu.net@hsvpmi.UUCP>
  10. Archive-Name: msdos-pipes
  11.  
  12. [I'm not so sure I see the point of this....  ++bsa]
  13.  
  14. Here is an MS-DOS version of the UN*X popen(3S) routine, inspired
  15. by an  off-the-cuff article from  the net  (no, I don't  have the
  16. reference... :-). It works under  TURBO-C, and is compatible with
  17. the MKS Toolkit (but it works fine without it).
  18.  
  19. Compile with  the -DDEMO switch  to generate a demo  program used
  20. like this:
  21.  
  22.     popen command ....
  23.  
  24. to  run  'command  ...'  from  a read-mode  pipe.  If  the  shell
  25. environment  variable  SHELL  is   set,  that  program  is  used;
  26. otherwise  the  variable  COMSPEC  is  used;  failing  all  that,
  27. COMMAND.COM in the current working directory is used.
  28.  
  29. Caveat programme...
  30.  
  31. ---------
  32. Tom Reynolds             voice: (205) 721-1200 x 303
  33. Phoenix microsystems, inc.     uucp:  ..!uunet!ingr!hsvpmi!reynolds
  34. 991 Discovery Drive        
  35. Huntsville, AL 35806     "First curse the darkness, then light the candle"
  36.  
  37.    o  /      o  /      o  /      o  /      o  /      o  /      o  /   
  38. ---- x ------- x ------- x ------- x ------- x ------- x ------- x ------- 
  39.    o  \      o  \      o  \      o  \      o  \      o  \      o  \   
  40. #! /bin/sh
  41. # This is a shell archive, meaning:
  42. # 1. Remove everything above the #! /bin/sh line.
  43. # 2. Save the resulting text in a file.
  44. # 3. Execute the file with /bin/sh (not csh) to create:
  45. #    getswitch.c
  46. #    makefile
  47. #    popen.c
  48. #    popen.h
  49. #    turboc.cfg
  50. # This archive created: Wed Mar  2 17:24:28 1988
  51. export PATH; PATH=/bin:/usr/bin:$PATH
  52. echo shar: "extracting 'getswitch.c'" '(274 characters)'
  53. if test -f 'getswitch.c'
  54. then
  55.     echo shar: "will not over-write existing file 'getswitch.c'"
  56. else
  57. sed 's/^    X//' << \SHAR_EOF > 'getswitch.c'
  58.     X#include <stdio.h>
  59.     X#include <dos.h>
  60.     X 
  61.     Xstatic    char    SW = 0;        /* DOS switch character, either '-' or '/' */
  62.     X
  63.     Xint
  64.     Xgetswitch()
  65.     X{
  66.     X   if (SW == 0) {
  67.     X      /* get SW using dos call 0x37 */
  68.     X      _AX = 0x3700;
  69.     X      geninterrupt(0x21);
  70.     X      SW = _DL;
  71.     X   }
  72.     X   return( SW & 0xFF );
  73.     X}
  74. SHAR_EOF
  75. if test 274 -ne "`wc -c < 'getswitch.c'`"
  76. then
  77.     echo shar: "error transmitting 'getswitch.c'" '(should have been 274 characters)'
  78. fi
  79. fi
  80. echo shar: "extracting 'makefile'" '(226 characters)'
  81. if test -f 'makefile'
  82. then
  83.     echo shar: "will not over-write existing file 'makefile'"
  84. else
  85. sed 's/^    X//' << \SHAR_EOF > 'makefile'
  86.     Xpopen.exe: popen.obj getswitch.obj
  87.     X    cc -epopen popen.obj getswitch.obj
  88.     X
  89.     Xpopen.obj: popen.c
  90.     X    cc -c -DDEMO popen.c
  91.     X
  92.     Xclean:
  93.     X    rm -f *.obj core *.map
  94.     X
  95.     Xclobber: clean
  96.     X    rm -f *.exe install
  97.     X    
  98.     Xinstall:
  99.     X    cc -c popen.c
  100.     X    @echo What next?
  101. SHAR_EOF
  102. if test 226 -ne "`wc -c < 'makefile'`"
  103. then
  104.     echo shar: "error transmitting 'makefile'" '(should have been 226 characters)'
  105. fi
  106. fi
  107. echo shar: "extracting 'popen.c'" '(9895 characters)'
  108. if test -f 'popen.c'
  109. then
  110.     echo shar: "will not over-write existing file 'popen.c'"
  111. else
  112. sed 's/^    X//' << \SHAR_EOF > 'popen.c'
  113.     X/* popen/pclose:
  114.     X *
  115.     X * simple MS-DOS piping scheme to imitate UNIX pipes
  116.     X */
  117.     X
  118.     X#include <stdio.h>
  119.     X#include <ctype.h>
  120.     X#include <alloc.h>
  121.     X#include <string.h>
  122.     X#include <errno.h>
  123.     X#include <setjmp.h>
  124.     X#include <process.h>
  125.     X
  126.     X#include "popen.h"
  127.     X
  128.     Xextern char *getenv( char * );
  129.     X
  130.     X#ifndef    _NFILE
  131.     X# define    _NFILE    OPEN_MAX    /* Number of open files */
  132.     X#endif    _NFILE
  133.     X
  134.     X#define READIT    1            /* Read pipe */
  135.     X#define WRITEIT    2            /* Write pipe */
  136.     X
  137.     Xstatic char *prgname[ _NFILE ];        /* program name if write pipe */
  138.     Xstatic int pipetype[ _NFILE ];        /* 1=read 2=write */
  139.     Xstatic char *pipename[ _NFILE ];    /* pipe file name */
  140.     X
  141.     X/*
  142.     X *------------------------------------------------------------------------
  143.     X * stoupper: Convert string to uppercase (in place)
  144.     X *------------------------------------------------------------------------
  145.     X */
  146.     X
  147.     Xstatic void
  148.     Xstoupper( s )
  149.     Xchar *s;
  150.     X{
  151.     X   int c;
  152.     X   for( ; (c = *s) != '\0'; ++s ) {
  153.     X      if( islower( c ) ) *s = _toupper( c );
  154.     X   }
  155.     X}
  156.     X
  157.     X/*
  158.     X *------------------------------------------------------------------------
  159.     X * strsave: Copy string into malloc'ed memory and return address
  160.     X *------------------------------------------------------------------------
  161.     X */
  162.     X 
  163.     Xstatic char *
  164.     Xstrsave( s )
  165.     Xchar *s;
  166.     X{
  167.     X   char *sp = malloc( strlen( s ) + 1 );
  168.     X   if( sp != (char *) NULL ) (void) strcpy( sp, s );
  169.     X   return( sp );
  170.     X}
  171.     X
  172.     X/*
  173.     X *------------------------------------------------------------------------
  174.     X * strfree: Returm strsave'd string memory
  175.     X *------------------------------------------------------------------------
  176.     X */
  177.     X
  178.     Xstatic void
  179.     Xstrfree( s )
  180.     Xchar *s;
  181.     X{
  182.     X   if( s != (char *) NULL ) free( s );
  183.     X}
  184.     X
  185.     X/*
  186.     X *------------------------------------------------------------------------
  187.     X * run: Execute command via SHELL or COMSPEC
  188.     X *------------------------------------------------------------------------
  189.     X */
  190.     X
  191.     Xstatic int
  192.     Xrun( command )
  193.     Xchar *command;
  194.     X{
  195.     X   jmp_buf panic;            /* How to recover from errors */
  196.     X   int lineno;                /* Line number where panic happened */
  197.     X   char *shell;                /* Command processor */
  198.     X   char *s = (char *) NULL;        /* Holds the command */
  199.     X   int s_is_malloced = 0;        /* True if need to free 's' */
  200.     X   static char *command_com = "COMMAND.COM";
  201.     X   int status;                /* Return codes */
  202.     X   char *shellpath;            /* Full command processor path */
  203.     X   char *bp;                /* Generic string pointer */
  204.     X   static char dash_c[ 3 ] = { '?', 'c', '\0' };
  205.     X   if( (lineno = setjmp( panic )) != 0 ) {
  206.     X      int E = errno;
  207.     X#ifdef    DEMO
  208.     X      fprintf( stderr, "RUN panic on line %d: %d\n", lineno, E );
  209.     X#endif    DEMO
  210.     X      if( s_is_malloced && (s != (char *) NULL) ) strfree( s );
  211.     X      errno = E;
  212.     X      return( -1 );
  213.     X   }
  214.     X   if( (s = strsave( command )) == (char *) NULL ) longjmp( panic, __LINE__ );
  215.     X   /* Determine the command processor */
  216.     X   if( ((shell = getenv( "SHELL" )) == (char *) NULL) &&
  217.     X       ((shell = getenv( "COMSPEC" )) == (char *) NULL) ) shell = command_com;
  218.     X   stoupper( shell );
  219.     X   shellpath = shell;
  220.     X   /* Strip off any leading backslash directories */
  221.     X   shell = strrchr( shellpath, '\\' );
  222.     X   if( shell != (char *) NULL ) ++shell;
  223.     X   else                         shell = shellpath;
  224.     X   /* Strip off any leading slash directories */
  225.     X   bp = strrchr( shell, '/'  );
  226.     X   if( bp != (char *) NULL ) shell = ++bp;
  227.     X   if( strcmp( shell, command_com ) != 0 ) {
  228.     X      /* MKS Shell needs quoted argument */
  229.     X      char *bp;
  230.     X      if( (bp = s = malloc( strlen( command ) + 3 )) == (char *) NULL ) 
  231.     X     longjmp( panic, __LINE__ );
  232.     X      *bp++ = '\'';
  233.     X      while( (*bp++ = *command++) != '\0' );
  234.     X      *(bp - 1) = '\'';
  235.     X      *bp = '\0';
  236.     X      s_is_malloced = 1;
  237.     X   } else s = command;
  238.     X   dash_c[ 0 ] = getswitch();
  239.     X   /* Run the program */
  240.     X#ifdef    DEMO
  241.     X   fprintf( stderr, "Running: (%s) %s %s %s\n", shellpath, shell, dash_c, s );
  242.     X#endif    DEMO
  243.     X   status = spawnl( P_WAIT, shellpath, shell, dash_c, s, (char *) NULL );
  244.     X   if( s_is_malloced ) free( s );
  245.     X   return( status );
  246.     X}
  247.     X
  248.     X/* 
  249.     X *------------------------------------------------------------------------
  250.     X * uniquepipe: returns a unique file name 
  251.     X *------------------------------------------------------------------------
  252.     X */
  253.     X
  254.     Xstatic char *
  255.     Xuniquepipe()
  256.     X{ 
  257.     X   static char name[ 14 ];
  258.     X   static short int num = 0;
  259.     X   (void) sprintf( name, "pipe%05d.tmp", num++ );
  260.     X   return( name );
  261.     X}
  262.     X
  263.     X/*
  264.     X *------------------------------------------------------------------------
  265.     X * resetpipe: Private routine to cancel a pipe
  266.     X *------------------------------------------------------------------------
  267.     X */
  268.     X
  269.     Xstatic void
  270.     Xresetpipe( fd )
  271.     Xint fd;
  272.     X{
  273.     X   char *bp;
  274.     X   if( (fd >= 0) && (fd < _NFILE) ) {
  275.     X      pipetype[ fd ] = 0;
  276.     X      if( (bp = pipename[ fd ]) != (char *) NULL ) {
  277.     X     (void) unlink( bp );
  278.     X     strfree( bp );
  279.     X     pipename[ fd ] = (char *) NULL;
  280.     X      }
  281.     X      if( (bp = prgname[ fd ]) != (char *) NULL ) {
  282.     X     strfree( bp );
  283.     X     prgname[ fd ] = (char *) NULL;
  284.     X      }
  285.     X   }
  286.     X}
  287.     X
  288.     X/* 
  289.     X *------------------------------------------------------------------------
  290.     X * popen: open a pipe 
  291.     X *------------------------------------------------------------------------
  292.     X */
  293.     X
  294.     XFILE *popen( prg, type )
  295.     Xchar *prg;            /* The command to be run */
  296.     Xchar *type;            /* "w" or "r" */
  297.     X{ 
  298.     X   FILE *p = (FILE *) NULL;    /* Where we open the pipe */
  299.     X   int ostdin;            /* Where our stdin is now */
  300.     X   int pipefd = -1;        /* fileno( p ) -- for convenience */
  301.     X   char tmpfile[ BUFSIZ ];    /* Holds name of pipe file */
  302.     X   char *tmpdir;        /* Points to directory prefix of pipe */
  303.     X   jmp_buf panic;        /* Where to go if there's an error */
  304.     X   int lineno;            /* Line number where panic happened */
  305.     X   /* Find out where we should put temporary files */
  306.     X   if( (tmpdir = getenv( "TMPDIR" )) == (char *) NULL ) 
  307.     X      tmpdir = getenv( "TMP" );
  308.     X   if( tmpdir != (char *) NULL ) {
  309.     X      /* Use temporary directory if available */
  310.     X      (void) strcpy( tmpfile, tmpdir );
  311.     X      (void) strcat( tmpfile, "/" );
  312.     X   } else *tmpfile = '\0';
  313.     X   /* Get a unique pipe file name */
  314.     X   (void) strcat( tmpfile, uniquepipe() );
  315.     X   if( (lineno = setjmp( panic )) != 0 ) {
  316.     X      /* An error has occurred, so clean up */
  317.     X      int E = errno;
  318.     X#ifdef    DEMO
  319.     X      fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
  320.     X#endif    DEMO
  321.     X      if( p != (FILE *) NULL ) (void) fclose( p );
  322.     X      resetpipe( pipefd );
  323.     X      errno = E;
  324.     X      return( (FILE *) NULL );
  325.     X   }
  326.     X   if( strcmp( type, "w" ) == 0 ) {
  327.     X      /* for write style pipe, pclose handles program execution */
  328.     X      if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
  329.     X     pipefd = fileno( p );
  330.     X     pipetype[ pipefd ] = WRITEIT;
  331.     X     pipename[ pipefd ] = strsave( tmpfile );
  332.     X     prgname[ pipefd ]  = strsave( prg );
  333.     X     if( !pipename[ pipefd ] || !prgname[ pipefd ] ) longjmp( panic, __LINE__ );
  334.     X      }
  335.     X   } else if( strcmp( type, "r" ) == 0 ) {
  336.     X      /* read pipe must create tmp file, set up stdout to point to the temp
  337.     X      * file, and run the program.  note that if the pipe file cannot be
  338.     X      * opened, it'll return a condition indicating pipe failure, which is
  339.     X      * fine.
  340.     X      */
  341.     X      if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
  342.     X     int ostdout;
  343.     X     pipefd = fileno( p );
  344.     X     pipetype[ pipefd ]= READIT;
  345.     X     if( (pipename[ pipefd ] = strsave( tmpfile )) == (char *) NULL ) 
  346.     X        longjmp( panic, __LINE__ );
  347.     X     /* Redirect stdin for the new command */
  348.     X     ostdout = dup( fileno( stdout ) );
  349.     X     if( dup2( fileno( stdout ), pipefd ) < 0 ) {
  350.     X        int E = errno;
  351.     X        (void) dup2( fileno( stdout ), ostdout );
  352.     X        errno = E;
  353.     X        longjmp( panic, __LINE__ );
  354.     X     }
  355.     X     if( run( prg ) != 0 ) longjmp( panic, __LINE__ );
  356.     X     if( dup2( fileno( stdout ), ostdout ) < 0 ) longjmp( panic, __LINE__ );
  357.     X     if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
  358.     X     if( (p = fopen( tmpfile, "r" )) == (FILE *) NULL ) longjmp( panic, __LINE__ );
  359.     X      }
  360.     X   } else {
  361.     X      /* screwy call or unsupported type */
  362.     X      errno = EINVFNC;
  363.     X      longjmp( panic, __LINE__ );
  364.     X   }
  365.     X   return( p );
  366.     X}
  367.     X
  368.     X/* close a pipe */
  369.     X
  370.     Xint
  371.     Xpclose( p )
  372.     XFILE *p;
  373.     X{
  374.     X   int pipefd = -1;        /* Fildes where pipe is opened */
  375.     X   int ostdout;            /* Where our stdout points now */
  376.     X   int ostdin;            /* Where our stdin points now */
  377.     X   jmp_buf panic;        /* Context to return to if error */
  378.     X   int lineno;            /* Line number where panic happened */
  379.     X   if( (lineno = setjmp( panic )) != 0 ) {
  380.     X      /* An error has occurred, so clean up and return */
  381.     X      int E = errno;
  382.     X#ifdef    DEMO
  383.     X      fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
  384.     X#endif    DEMO
  385.     X      if( p != (FILE *) NULL ) (void) fclose( p );
  386.     X      resetpipe( pipefd );
  387.     X      errno = E;
  388.     X      return( -1 );
  389.     X   }
  390.     X   pipefd = fileno( p );
  391.     X   if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
  392.     X   switch( pipetype[ pipefd ] ) {
  393.     X      case WRITEIT:
  394.     X     /* open the temp file again as read, redirect stdin from that
  395.     X      * file, run the program, then clean up.
  396.     X      */
  397.     X      if( (p = fopen( pipename[ pipefd ],"r" )) == (FILE *) NULL ) 
  398.     X     longjmp( panic, __LINE__ );
  399.     X      ostdin = dup( fileno( stdin ));
  400.     X      if( dup2( fileno( stdin ), fileno( p ) ) < 0 ) longjmp( panic, __LINE__ );
  401.     X      if( run( prgname[ pipefd ] ) != 0 ) longjmp( panic, __LINE__ );
  402.     X      if( dup2( fileno( stdin ), ostdin ) < 0 ) longjmp( panic, __LINE__ );
  403.     X      if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
  404.     X      resetpipe( pipefd );
  405.     X      break;
  406.     X   case READIT:
  407.     X      /* close the temp file and remove it */
  408.     X      resetpipe( pipefd );
  409.     X      break;
  410.     X   default:
  411.     X      errno = EINVFNC;
  412.     X      longjmp( panic, __LINE__ );
  413.     X      /*NOTREACHED*/
  414.     X   }
  415.     X   return( 0 );
  416.     X}
  417.     X
  418.     X#ifdef    DEMO
  419.     Xint
  420.     Xmain( argc, argv )
  421.     Xint argc;
  422.     Xchar **argv;
  423.     X{
  424.     X   FILE *pipe;
  425.     X   char buf[ BUFSIZ ];
  426.     X   int n;
  427.     X   *buf = '\0';
  428.     X   for( n = 1; n < argc; ++n ) {
  429.     X      (void) strcat( buf, argv[ n ] );
  430.     X      (void) strcat( buf, " " );
  431.     X   }
  432.     X   if( (pipe = popen( buf, "r" )) != (FILE *) NULL ) {
  433.     X      while( fgets( buf, sizeof( buf ), pipe ) != (char *) NULL ) 
  434.     X     (void) fputs( buf, stdout );
  435.     X      if( pclose( pipe ) != 0 ) fprintf( stderr, "error closing pipe!\n" );
  436.     X   } else fprintf( stderr, "it didn't work!\n" );
  437.     X   exit( 0 );
  438.     X   /*NOTREACHED*/
  439.     X}
  440.     X#endif    DEMO
  441. SHAR_EOF
  442. if test 9895 -ne "`wc -c < 'popen.c'`"
  443. then
  444.     echo shar: "error transmitting 'popen.c'" '(should have been 9895 characters)'
  445. fi
  446. fi
  447. echo shar: "extracting 'popen.h'" '(67 characters)'
  448. if test -f 'popen.h'
  449. then
  450.     echo shar: "will not over-write existing file 'popen.h'"
  451. else
  452. sed 's/^    X//' << \SHAR_EOF > 'popen.h'
  453.     Xextern FILE *popen( char *, char * );
  454.     Xextern int pclose( FILE * );
  455. SHAR_EOF
  456. if test 67 -ne "`wc -c < 'popen.h'`"
  457. then
  458.     echo shar: "error transmitting 'popen.h'" '(should have been 67 characters)'
  459. fi
  460. fi
  461. echo shar: "extracting 'turboc.cfg'" '(76 characters)'
  462. if test -f 'turboc.cfg'
  463. then
  464.     echo shar: "will not over-write existing file 'turboc.cfg'"
  465. else
  466. sed 's/^    X//' << \SHAR_EOF > 'turboc.cfg'
  467.     X-LC:\TURBOC\LIB -IC:\TURBOC\INCLUDE -IC:\TURBOC\INCLUDE\SYS -ms -DTURBOC -M
  468. SHAR_EOF
  469. if test 76 -ne "`wc -c < 'turboc.cfg'`"
  470. then
  471.     echo shar: "error transmitting 'turboc.cfg'" '(should have been 76 characters)'
  472. fi
  473. fi
  474. exit 0
  475. #    End of shell archive
  476.